home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
019a
/
opbgd113.zip
/
OPBIGED.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1991-10-21
|
64KB
|
2,382 lines
{$A+,F+,O+,R-,S-,V-}
{$I OPDEFINE.INC}
{*********************************************************}
{* OPBIGED.PAS 1.13 *}
{* Copyright (c) TurboPower Software 1991. *}
{* All rights reserved. *}
{*********************************************************}
unit OpBigEd;
{$IFNDEF UseMouse}
{$UNDEF UseDrag}
{$ENDIF}
interface
uses
DOS,
OpInline,
OpRoot,
OpDos,
OpString,
OpAsciiZ,
OpCrt,
{$IFDEF UseMouse}
OpMouse,
{$ENDIF}
OpCmd,
{$IFDEF UseDrag}
OpDrag,
{$ENDIF}
OpFrame,
OpWindow;
{$I OPBIGED.ICD}
const
AbsMaxAsciiZ : Integer = MaxInt; {our absolute max line length}
MemSafetySize = 4096; {minimum 4K heap safety pool}
const
beInsert = $00000001; {True if in insert mode}
beIndent = $00000002; {True if in auto-indent mode}
beReadOnly = $00000004; {True if in read-only mode}
beWordWrap = $00000008; {True if word wrap is on}
beDeleteJoins = $00000010; {True if <Del> can join lines}
beModified = $00000020; {True if edits have been made}
beIndentIsPara = $00000040; {indent starts paragraph?}
beMousePage = $00000080; {clicking on scroll bar scrolls by page}
beDeTab = $00000100; {expand tabs on reads?} {!!}
beEnTab = $00000200; {compress tabs on writes?} {!!}
beMapCtrls = $00000400; {map control characters?}
beMakeBackups = $00000800; {make backup files?}
beReformatting = $00001000; {flag set while reformatting}
beNewFile = $00002000; {new file loaded}
beWrapAtLeft = $00004000; {wrap to prev line on <Left> at column 1}
beReadPartial = $00008000; {allow partial reads if file too large?} {!!.13c}
beStripHigh = $00010000; {strip hi bits when reading a file}
beNoRepeatGlobal = $00020000; {flag to not repeat global search}
beForceRedraw = $00040000; {force entire screen to be updated} {!!}
beBlockOK = $00080000; {set if block is currently OK} {!!}
beHighlightCurr = $00100000; {set if the current line is highlighted} {!!}
beColumnBlock = $00200000; {set if in column-block mode} {!!}
beNoDispList = $00400000; {set to dispose list on call to Done} {!!}
beInProcess = $00800000; {internal flag set while in Process}
beSmartTabs = $01000000; {smart tabs or fixed tabs?}
beSearching = $02000000; {flag set while searching}
beDragBlock = $04000000; {set if dragblocking is on} {!!}
beHighlightOn = $10000000; {set if highlighting on in a search}
beHighlightBack = $20000000; {highlighting goes backwards?}
beMarkersOn = $40000000; {text markers visible?}
beBlockOn = $80000000; {block markers on?}
DefBigEdOptions : LongInt = beInsert+beIndent+beDeleteJoins+beMapCtrls+
beMousePage+beMakeBackups+beSmartTabs+beDeTab+
beReadPartial+beForceRedraw;
BadBigEdOptions : LongInt = beModified+beReformatting+beSearching+beBlockOK+
beHighlightOn+beHighlightBack+beInProcess+
beDragBlock+beColumnBlock;
const
DefBlockIndent : Integer = 2;
DefTabSize : Integer = 8;
LPTNum : Char = '1';
WrapDelims : CharSet = [^I, ' ', '-'];
SpaceDelims : CharSet = [^I, ' '];
WordDelims : CharSet = [^I, ' '..'"', '.', ',', ':', ';', '?', '!',
'*', '(', ')', '[', ']', '{', '}', '<', '>',
'+', '-', '/', '\', '''', '$', '=', '^', '#'];
MaxSearchLen = 30; {Maximum length of search string}
MaxBlockIndent = 10; {max indent level allowed}
{search option characters}
MaxSearchOptions = 5;
beBackward = 'B';
beNoCase = 'U';
beGlobal = 'G';
beNoConfirm = 'N';
beBlockOnly = 'L';
{codes for yes-no functions}
beNo = 0;
beYes = 1;
beQuit = 2;
beAll = 3;
const
{the commands in this set are disallowed in read-only mode}
DisallowedInReadOnlyMode : set of Byte =
[ccChar, ccCtrlChar, ccSelect, ccInsertLine, ccBack, ccDel, ccRestore,
ccDelEol, ccDelLine, ccDelWord, ccIns, ccTab, ccIndent, ccWordWrap,
ccReformatP, ccReformatG,
ccCenterLine, ccSaveFile, ccSaveNamed, ccSaveSwitch, ccSaveExit,
ccBlkCopy, ccBlkMove, ccBlkDelete, ccBlkUCase, ccBlkLCase,
ccBlkTCase, ccBlkIndent, ccBlkUnindent, ccBlkRead, ccReplace];
const
{I/O buffer size. **Warning** these buffers are allocated on the stack!}
MaxFBuf = 8192;
type
{I/O buffer type}
IOBuf = Array[1..MaxFBuf] of Char;
type
{object for each line}
PLine = ^LineNode;
LineNode =
object(DoubleListNode)
St : AsciiZPtr;
Len : Integer;
Size : Integer;
Blocked : Boolean;
NoTrim : Boolean;
constructor Init(S : AsciiZPtr);
{-init object}
destructor Done; virtual;
{-dispose of it when finished}
function lnUpdate(S : AsciiZPtr) : Word;
{-update the string pointer in the node to the new string}
function lnLen : Integer;
{-return the length of the stored string}
end;
{DoubleList with our special needs}
LineListPtr = ^LineList;
LineList =
object(DoubleList)
function Num(P : DoubleNodePtr) : Word;
{-return the position in the list of P, 0 if nil or not in list}
procedure Clean;
{-clear the list of all nodes}
function OfsLine(SP : PLine; OfsL : Integer) : PLine;
{-return PLine that is OfsL lines down from SP}
end;
MarkerType = (mtBlockBegin, mtBlockEnd, mtMarker);
MarkerRec =
record
LP : PLine;
CP : Integer;
end;
const
MaxMarker = 3;
type
beChangeCaseType = (beToUpper, beToLower, beToggle);
beSearchType = (bescNone, bescSearch, bescReplace);
beCharType = (beAlpha, beWhite, bePunct);
MarkerSet = Array[0..MaxMarker] of MarkerRec;
beYesNoFunc = function(MsgCode : Word; Prompt : string;
Default : Byte; QuitAndAll : Boolean) : Byte;
beEditFunc = function(MsgCode : Word; Prompt : string;
ForceUp, TrimBlanks : Boolean;
MaxLen : Byte; var S : string) : Boolean;
beGetFileFunc = function(MsgCode : Word; Prompt : string;
ForceUp, TrimBlanks, Writing, MustExist : Boolean;
MaxLen : Byte; DefExt : ExtStr;
var S : string) : Boolean;
MStateRec =
record
LNum : Integer;
CNum : Integer;
end;
StreamStateRec =
record
SSTNum : Integer;
SSLOfs : Integer;
SSCPos : Integer;
SSCOfs : Integer;
SSOptions : LongInt;
SSTabSize : Integer;
SSBlockIndent: Integer;
SSMargin : Integer;
SSBlockBegin : MStateRec;
SSBlockEnd : MStateRec;
SSMarkers : Array[0..MaxMarker] of MStateRec;
end;
BigEditorPtr = ^BigEditor;
beStatusProc = procedure(BEP : BigEditorPtr);
BigEditor =
object(CommandWindow)
LList : LineListPtr; {our list of lines}
TList : LineListPtr; {second list for block ops, etc.}
Top : PLine; {top line of window}
TNum : Integer; {number of top line}
Cur : PLine; {current edit line}
LOfs : Integer; {offset of current line from Top (>= 0)}
CPos : Integer; {vert. cursor pos in window}
COfs : Integer; {cols offset of left window margin (>= 0)}
Work : AsciiZPtr; {workspace vars}
Temp : AsciiZPtr;
beOptions : LongInt; {options longint}
beTabSize : Byte; {size of tabstops for fixed tabs}
beBlockIndent : Integer; {block indention level}
beMargin : Integer; {right margin}
beLPTNum : Char; {printer port number (1-3)}
beBlockBegin : MarkerRec; {block and text markers}
beBlockEnd : MarkerRec;
beMarkers : MarkerSet;
beMarkerFlags : Word;
beLastPosition : MarkerRec;
beSearchSt : string[MaxSearchLen]; {String to search for}
beReplaceSt : string[MaxSearchLen]; {String to replace it with}
beOptionSt : string[MaxSearchOptions]; {Search options}
beLastSearch : beSearchType; {Type of last search operation}
beStatus : beStatusProc; {our proc ptrs}
beYesNoP : beYesNoFunc;
beEditP : beEditFunc;
beGetFileP : beGetFileFunc;
beCtrlColor, beCtrlMono : Byte; {our attributes}
beBlockColor, beBlockMono : Byte;
beHighlightColor, beHighlightMono : Byte;
beMarkerColor, beMarkerMono : Byte;
TA, CA, BA, HA, MA : Byte; {attribute bytes}
bePathName : PathStr; {pathname of current file}
beDefExt : ExtStr; {default extension}
SearchLine : PLine; {used in text search/replace}
SaveCnt : Word; {used by UpdateScrollBars}
constructor Init(UX, UY, LX, LY : Byte);
{-initialize a BigEditor with default colors and options}
constructor InitCustom(UX, UY, LX, LY : Byte;
var Colors : ColorSet;
WinOpts : LongInt);
{-initialize a BigEditor with custom colors and options}
constructor InitDeluxe(UX, UY, LX, LY : Byte;
var Colors : ColorSet;
WinOpts : LongInt;
WorkList : LineListPtr);
{-initialize a BigEditor using a already-allocated LineList}
destructor Done; virtual;
{-destroy object when done}
{...public methods}
function YesNo(MsgCode : Word; Prompt : string;
Default : Byte; QuitAndAll : Boolean) : Byte; virtual;
function Edit(MsgCode : Word; Prompt : string;
ForceUp, TrimBlanks : Boolean;
MaxLen : Byte; var S : string) : Boolean; virtual;
function GetFile(MsgCode : Word; Prompt : string;
ForceUp, TrimBlanks, Writing, MustExist : Boolean;
MaxLen : Byte; DefExt : ExtStr;
var S : string) : Boolean; virtual;
procedure beOptionsOn(L : LongInt);
{-turn on one or more options}
procedure beOptionsOff(L : LongInt);
{-turn off one or more options}
function beOptionsAreOn(L : LongInt) : Boolean;
{-true if all requested options are on}
procedure beToggleOption(L : LongInt);
{-invert the state of an option}
procedure SetStatusProc(SP : beStatusProc);
{-set our status procedure}
procedure SetYesNoProc(YNF : beYesNoFunc);
{-set our Yes/No function}
procedure SetEditProc(EF : beEditFunc);
{-set our edit function}
procedure SetGetFileProc(GFF : beGetFileFunc);
{-set our function to get a filename}
procedure SetTextAttr(Color, Mono : Byte); virtual;
{-set attributes for normal text}
procedure SetBlockAttr(Color, Mono : Byte);
{-Set attributes for marked blocks}
procedure SetMarkerAttr(Color, Mono : Byte);
{-Set attributes for text markers and found text}
procedure SetHighlightAttr(Color, Mono : Byte);
{-Set attributes for highlighted current line}
procedure SetCtrlAttr(Color, Mono : Byte);
{-Set attributes for mapped control characters}
procedure SetBlockIndent(Indent : Integer);
{-Set block indentation level}
procedure SetDefaultExtension(DefExt : ExtStr);
{-Default extension to use when prompting for filenames}
procedure SetPrinter(LptNum : Integer);
{-Set printer (1-3)}
{...virtual methods}
procedure SaveState(var S); virtual;
{-save the state of the current text stream into S}
procedure RestoreState(var S); virtual;
{-restore the state of the current stream from S}
procedure ReadFile(FName : string; var FSize : LongInt); virtual;
{-read a file into the editor}
procedure SaveFile; virtual;
{-save the current text stream to a file}
procedure SaveNamedFile; virtual;
{-save the stream under a different name}
procedure UpdateContents; virtual;
{-redraw the editor window}
procedure NewFilePrompted; virtual;
{-get a name for a new file and load it}
procedure ProcessSelf; virtual;
{-edit the text stream}
{...private methods}
function CurLine : PLine;
function CurCol : Integer;
procedure SaveStatePrim(var S : StreamStateRec);
procedure RestoreStatePrim(var S : StreamStateRec);
function Split(T, C : PLine) : Integer;
procedure ResetStream;
procedure beReadFilePrim(FName : string; var FSize : LongInt;
ErrorPrefix : Word);
procedure beUpdateContents;
procedure AdjustCursorToWindow;
procedure OfsToPLine(P : PLine);
procedure SplitLinePrim(At : Integer);
function SplitLine(P : PLine; At : Integer) : PLine;
function LeadingWhite(P : PLine) : Integer;
procedure ChTopLine(Num : Integer);
procedure ChLine(Num : Integer);
procedure ChCursor(Num : Integer);
procedure CursorToHome;
procedure CursorToEnd;
procedure CursorToCol(Col : Integer);
procedure WordLeft;
procedure WordRight;
procedure TopOfFile;
procedure EndOfFile;
procedure GetWork(P : PLine);
procedure GetTemp(P : PLine);
procedure GetCurLine;
procedure GetCurLineTemp;
procedure HandleChar(Ch : Char);
procedure WordWrap(Src, OvrLap : AsciiZPtr; Margin : Integer);
procedure HandleCR(MoveCursor : Boolean);
procedure HandleBS;
procedure HandleTab;
procedure DelChar;
procedure DelEOL;
procedure DelWord;
procedure DelLine;
procedure GoToLinePtr(P : PLine);
procedure GoToLineNum(N : Integer);
procedure GoToLineCol(L, C : Integer);
procedure GoToMarker(var M : MarkerRec);
procedure DropMarker(L : PLine; C : Integer);
procedure SetTextMarker(Num : Integer);
function MemForBlock : LongInt;
function BlockContiguous : Boolean;
procedure ConnectBlocking;
procedure CleanBlocking;
function LineInBlock(P : PLine) : Boolean;
function CursorInBlock(ChkCol : Boolean) : Boolean;
procedure CharsInserted(P : PLine; At, Num : Integer);
procedure LineDeleted(P : PLine);
procedure LinesBroken(P : PLine; At : Integer);
procedure LinesJoined(P : PLine; At : Integer);
function BlockToList(var L : LineList) : Boolean;
procedure BlockFromList(var L : LineList);
procedure MarkWordAsBlock;
function DeleteBlockPrim : Boolean;
procedure CopyBlock;
procedure MoveBlock;
procedure DeleteBlock;
function ReadBlockPrim(var Lst : LineList) : Boolean;
procedure ReadBlock;
procedure WriteBlock(ToPrn : Boolean);
procedure IndentBlock(Spaces : Integer);
procedure ChangeCaseBlock(CT : beChangeCaseType);
procedure CopyToClipboard(Cut : Boolean);
procedure PasteFromClipboard;
procedure TextSearch(Prompt : Boolean; SearchType : beSearchType);
procedure ReformatParagraph;
procedure ReformatGlobal;
procedure CenterLine;
{$IFDEF UseScrollBars}
procedure UpdateScrollBars;
{$ENDIF}
{$IFDEF UseMouse}
function ProcessMouseCommand(Cmd : Byte) : Boolean;
{$ENDIF}
end;
var
{$IFDEF UseDrag}
BigEditorCommands : DragProcessor;
{$ELSE}
BigEditorCommands : CommandProcessor;
{$ENDIF}
ClipBoard : LineList;
procedure NoBigEditorStatus(BEP : BigEditorPtr);
implementation
{globals used in TextSearches}
var
NoCase : Boolean;
Backwards : Boolean;
NoConfirm : Boolean;
BlockOnly : Boolean;
Global : Boolean;
Status : Word; {handy var for error checking}
procedure NoBigEditorStatus(BEP : BigEditorPtr);
begin
; {do-nothing proc}
end;
{--- LineNode methods -------------------------------------------------------}
constructor LineNode.Init(S : AsciiZPtr);
begin
if NOT DoubleListNode.Init then
Fail;
Len := LenAsc(S^)+1;
if Len > AbsMaxAsciiZ then
Fail;
Size := ((Len shr 3) + 1) shl 3;
if NOT GetMemCheck(St, Size) then
Fail;
FillChar(St^, Size, 0);
MoveFast(S^, St^, Len);
Blocked := False;
NoTrim := False;
end;
destructor LineNode.Done;
begin
FreeMemCheck(St, Size);
DoubleListNode.Done;
end;
function LineNode.lnUpdate(S : AsciiZPtr) : Word;
var
X : Integer;
W : Word;
begin
W := LenAsc(S^);
if W > AbsMaxAsciiZ then begin
lnUpdate := ecLineTooLong;
exit;
end;
X := (((W+1) shr 3) + 1) shl 3;
if Size <> X then begin
FreeMemCheck(St, Size);
Size := X;
if NOT GetMemCheck(St, Size) then begin
lnUpdate := ecOutOfMemory;
exit;
end;
end;
FillChar(St^, Size, 0);
Len := W;
MoveFast(S^, St^, Len);
if not NoTrim then begin
while (Len > 0) and (St^[Len-1] = ' ') do begin
St^[Len-1] := #0;
Dec(Len);
end;
Inc(Len);
end;
lnUpdate := 0;
end;
function LineNode.lnLen : Integer;
begin
lnLen := Len-1;
end;
{--- LineList methods -------------------------------------------------------}
function LineList.Num(P : DoubleNodePtr) : Word;
var W : Word;
N : DoubleNodePtr;
begin
Num := 0;
if P = nil then exit;
W := 1;
N := dlHead;
while (N <> P) do begin
Inc(W);
N := N^.dlNext;
if N = nil then exit;
end;
Num := W;
end;
procedure LineList.Clean;
var N : DoubleNodePtr;
P : DoubleNodePtr;
begin
N := dlTail;
while N <> nil do begin
P := N^.dlPrev;
if OS(N).S >= OS(HeapOrg).S then
Dispose(N, Done)
else
N^.Done;
N := P;
end;
dlTail := nil;
dlHead := nil;
dlSize := 0;
end;
function LineList.OfsLine(SP : PLine; OfsL : Integer) : PLine;
var
P : PLine;
W : Integer;
begin
P := SP;
W := 0;
while (P <> nil) and (W <> OfsL) do begin
P := PLine(P^.dlNext);
Inc(W);
end;
OfsLine := P;
end;
{--- BigEditor methods ------------------------------------------------------}
constructor BigEditor.Init(UX, UY, LX, LY : Byte);
begin
if not BigEditor.InitCustom(UX, UY, LX, LY, DefaultColorSet, DefWindowOptions) then
Fail;
end;
constructor BigEditor.InitCustom(UX, UY, LX, LY : Byte;
var Colors : ColorSet;
WinOpts : LongInt);
begin
if not CommandWindow.InitCustom(UX, UY, LX, LY, Colors, WinOpts,
BigEditorCommands, ucNone) then Fail;
New(LList, Init);
if LList = nil then begin
InitStatus := epFatal+ecOutOfMemory;
Fail;
end;
New(TList, Init);
if TList = nil then begin
InitStatus := epFatal+ecOutOfMemory;
Dispose(LList,Done);
Fail;
end;
if not GetMemCheck(Work, AbsMaxAsciiZ) then begin
InitStatus := epFatal+ecOutOfMemory;
Dispose(TList,Done);
Dispose(LList,Done);
Fail;
end;
if not GetMemCheck(Temp, AbsMaxAsciiZ) then begin
InitStatus := epFatal+ecOutOfMemory;
FreeMemCheck(Work, AbsMaxAsciiZ);
Dispose(TList,Done);
Dispose(LList,Done);
Fail;
end;
Str2Asc('', Work^);
New(Top, Init(Work));
if Top = nil then begin
InitStatus := epFatal+ecOutOfMemory;
FreeMemCheck(Temp, AbsMaxAsciiZ);
FreeMemCheck(Work, AbsMaxAsciiZ);
Dispose(TList,Done);
Dispose(LList,Done);
Fail;
end;
LList^.Append(Top);
ResetStream;
beOptions := DefBigEdOptions;
beTabSize := DefTabSize;
beBlockIndent := DefBlockIndent;
beMargin := Width-3;
beLPTNum := LPTNum;
FillChar(beBlockBegin, SizeOf(beBlockBegin), 0);
FillChar(beBlockEnd, SizeOf(beBlockEnd), 0);
FillChar(beMarkers, SizeOf(beMarkers), 0);
FillChar(beLastPosition, SizeOf(beLastPosition), 0);
beMarkerFlags := 0;
beSearchSt := '';
beReplaceSt := '';
beOptionSt := '';
beLastSearch := bescNone;
beStatus := NoBigEditorStatus;
@beYesNoP := nil;
@beEditP := nil;
@beGetFileP := nil;
bePathName := '';
beDefExt := '';
SaveCnt := $FFFF;
with Colors do begin
beCtrlColor := CtrlColor;
beCtrlMono := CtrlMono;
beBlockColor := BlockColor;
beBlockMono := BlockMono;
beMarkerColor := MarkerColor;
beMarkerMono := MarkerMono;
beHighlightColor := HighlightColor;
beHighlightMono := HighlightMono;
end;
TA := ColorMono(wTextColor, wTextMono);
CA := ColorMono(beCtrlColor, beCtrlMono);
BA := ColorMono(beBlockColor, beBlockMono);
MA := ColorMono(beMarkerColor, beMarkerMono);
HA := ColorMono(beHighlightColor, beHighlightMono);
end;
constructor BigEditor.InitDeluxe(UX, UY, LX, LY : Byte;
var Colors : ColorSet;
WinOpts : LongInt;
WorkList : LineListPtr);
begin
if not CommandWindow.InitCustom(UX, UY, LX, LY, Colors, WinOpts,
BigEditorCommands, ucNone) then Fail;
LList := WorkList;
New(TList, Init);
if TList = nil then begin
InitStatus := epFatal+ecOutOfMemory;
Dispose(LList,Done);
Fail;
end;
if not GetMemCheck(Work, AbsMaxAsciiZ) then begin
InitStatus := epFatal+ecOutOfMemory;
Dispose(TList,Done);
Fail;
end;
if not GetMemCheck(Temp, AbsMaxAsciiZ) then begin
InitStatus := epFatal+ecOutOfMemory;
FreeMemCheck(Work, AbsMaxAsciiZ);
Dispose(TList,Done);
Fail;
end;
Str2Asc('', Work^);
New(Top, Init(Work));
if Top = nil then begin
InitStatus := epFatal+ecOutOfMemory;
FreeMemCheck(Temp, AbsMaxAsciiZ);
FreeMemCheck(Work, AbsMaxAsciiZ);
Dispose(TList,Done);
Fail;
end;
LList^.Append(Top);
ResetStream;
beOptions := DefBigEdOptions + beNoDispList;
beTabSize := DefTabSize;
beBlockIndent := DefBlockIndent;
beMargin := Width-3;
beLPTNum := LPTNum;
FillChar(beBlockBegin, SizeOf(beBlockBegin), 0);
FillChar(beBlockEnd, SizeOf(beBlockEnd), 0);
FillChar(beMarkers, SizeOf(beMarkers), 0);
FillChar(beLastPosition, SizeOf(beLastPosition), 0);
beMarkerFlags := 0;
beSearchSt := '';
beReplaceSt := '';
beOptionSt := '';
beLastSearch := bescNone;
beStatus := NoBigEditorStatus;
@beYesNoP := nil;
@beEditP := nil;
@beGetFileP := nil;
bePathName := '';
beDefExt := '';
SaveCnt := $FFFF;
with Colors do begin
beCtrlColor := CtrlColor;
beCtrlMono := CtrlMono;
beBlockColor := BlockColor;
beBlockMono := BlockMono;
beMarkerColor := MarkerColor;
beMarkerMono := MarkerMono;
beHighlightColor := HighlightColor;
beHighlightMono := HighlightMono;
end;
TA := ColorMono(wTextColor, wTextMono);
CA := ColorMono(beCtrlColor, beCtrlMono);
BA := ColorMono(beBlockColor, beBlockMono);
MA := ColorMono(beMarkerColor, beMarkerMono);
HA := ColorMono(beHighlightColor, beHighlightMono);
end;
destructor BigEditor.Done;
begin
FreeMemCheck(Temp, AbsMaxAsciiZ);
FreeMemCheck(Work, AbsMaxAsciiZ);
Dispose(TList,Done);
{if "fast" Done, don't clean list...}
if not LongFlagIsSet(beOptions, beNoDispList) then
Dispose(LList,Done);
CommandWindow.Done;
end;
function BigEditor.CurLine : PLine;
begin
CurLine := LList^.OfsLine(Top, LOfs);
end;
function BigEditor.CurCol : Integer;
begin
CurCol := CPos+COfs-1;
end;
procedure BigEditor.SaveStatePrim(var S : StreamStateRec);
var
W : Word;
I : Integer;
begin
with S do begin
SSTNum := TNum;
SSLOfs := LOfs;
SSCPos := CPos;
SSCOfs := COfs;
SSOptions := beOptions;
SSTabSize := beTabSize;
SSMargin := beMargin;
SSBlockIndent := beBlockIndent;
with SSBlockBegin do begin
LNum := LList^.Num(beBlockBegin.LP);
CNum := beBlockBegin.CP;
end;
with SSBlockEnd do begin
LNum := LList^.Num(beBlockEnd.LP);
CNum := beBlockEnd.CP;
end;
for I := 0 to MaxMarker do
with SSMarkers[i] do begin
LNum := LList^.Num(beMarkers[i].LP);
CNum := beMarkers[i].CP;
end;
end;
end;
procedure BigEditor.SaveState(var S);
begin
SaveStatePrim(StreamStateRec(S));
end;
procedure BigEditor.RestoreStatePrim(var S : StreamStateRec);
var
P : PLine;
I : Integer;
begin
with S do begin
TNum := SSTNum;
Top := PLine(LList^.Nth(TNum));
LOfs := SSLOfs;
CPos := SSCPos;
COfs := SSCOfs;
beOptions := SSOptions;
beTabSize := SSTabSize;
beMargin := SSMargin;
beBlockIndent := SSBlockIndent;
beBlockBegin.LP := PLine(LList^.Nth(SSBlockBegin.LNum));
beBlockBegin.CP := SSBlockBegin.CNum;
beBlockEnd.LP := PLine(LList^.Nth(SSBlockEnd.LNum));
beBlockEnd.CP := SSBlockEnd.CNum;
if BlockContiguous then
ConnectBlocking
else
ClearLongFlag(beOptions, beBlockOn);
for I := 0 to MaxMarker do begin
beMarkers[i].LP := PLine(LList^.Nth(SSMarkers[i].LNum));
beMarkers[i].CP := SSMarkers[i].CNum;
end;
SetLongFlag(beOptions, beForceRedraw+beNewFile);
end;
end;
procedure BigEditor.RestoreState(var S);
begin
RestoreStatePrim(StreamStateRec(S));
end;
function BigEditor.YesNo(MsgCode : Word; Prompt : string;
Default : Byte; QuitAndAll : Boolean) : Byte;
begin
if @beYesNoP <> nil then
YesNo := beYesNoP(MsgCode, Prompt, Default, QuitAndAll)
else
YesNo := beQuit;
end;
function BigEditor.Edit(MsgCode : Word; Prompt : string;
ForceUp, TrimBlanks : Boolean;
MaxLen : Byte; var S : string) : Boolean;
begin
if @beEditP = nil then
Edit := False
else
Edit := beEditP(MsgCode, Prompt, ForceUp, TrimBlanks, MaxLen, S);
end;
function BigEditor.GetFile(MsgCode : Word; Prompt : string;
ForceUp, TrimBlanks, Writing, MustExist : Boolean;
MaxLen : Byte; DefExt : ExtStr;
var S : string) : Boolean;
begin
if @beGetFileP = nil then
GetFile := False
else
GetFile := beGetFileP(MsgCode, Prompt, ForceUp, TrimBlanks,
Writing, MustExist, MaxLen, DefExt, S);
end;
procedure BigEditor.beOptionsOn(L : LongInt);
begin
SetLongFlag(beOptions, L and not BadBigEdOptions);
end;
procedure BigEditor.beOptionsOff(L : LongInt);
begin
ClearLongFlag(beOptions, L and not BadBigEdOptions);
end;
function BigEditor.beOptionsAreOn(L : LongInt) : Boolean;
begin
beOptionsAreOn := LongFlagIsSet(beOptions, L);
end;
procedure BigEditor.SetTextAttr(Color, Mono : Byte);
{-change the default attribute for marked blocks}
begin
wTextColor := Color;
wTextMono := MapMono(Color, Mono);
TA := ColorMono(wTextColor, wTextMono);
end;
procedure BigEditor.SetBlockAttr(Color, Mono : Byte);
{-change the default attribute for marked blocks}
begin
beBlockColor := Color;
beBlockMono := MapMono(Color, Mono);
BA := ColorMono(beBlockColor, beBlockMono);
end;
procedure BigEditor.SetMarkerAttr(Color, Mono : Byte);
{-change the default attribute for text markers}
begin
beMarkerColor := Color;
beMarkerMono := MapMono(Color, Mono);
MA := ColorMono(beMarkerColor, beMarkerMono);
end;
procedure BigEditor.SetHighlightAttr(Color, Mono : Byte);
{-change the default attribute for highlighting the current line}
begin
beHighlightColor := Color;
beHighlightMono := MapMono(Color, Mono);
HA := ColorMono(beHighlightColor, beHighlightMono);
end;
procedure BigEditor.SetCtrlAttr(Color, Mono : Byte);
{-change the default attribute for mapped control characters}
begin
beCtrlColor := Color;
beCtrlMono := MapMono(Color, Mono);
CA := ColorMono(beCtrlColor, beCtrlMono);
end;
procedure BigEditor.SetBlockIndent(Indent : Integer);
{-Set block indentation level}
begin
if Indent > MaxBlockIndent then
beBlockIndent := MaxBlockIndent
else if Indent > 0 then
beBlockIndent := Indent;
end;
procedure BigEditor.SetDefaultExtension(DefExt : ExtStr);
{-Default extension to use when prompting for filenames}
begin
beDefExt := DefExt;
end;
procedure BigEditor.SetPrinter(LptNum : Integer);
begin
if (LptNum < 1) or (LptNum > 3) then exit;
beLPTNum := Chr(LptNum + Ord('0'));
end;
procedure BigEditor.beToggleOption(L : LongInt);
begin
if LongFlagIsSet(beOptions, L) then
ClearLongFlag(beOptions, L)
else
SetLongFlag(beOptions, L);
end;
procedure BigEditor.SetStatusProc(SP : beStatusProc);
begin
beStatus := SP;
end;
procedure BigEditor.SetYesNoProc(YNF : beYesNoFunc);
begin
beYesNoP := YNF;
end;
procedure BigEditor.SetEditProc(EF : beEditFunc);
begin
beEditP := EF;
end;
procedure BigEditor.SetGetFileProc(GFF : beGetFileFunc);
begin
beGetFileP := GFF;
end;
{-----------------------------------------------------}
function BigEditor.Split(T, C : PLine) : Integer;
var
I : Integer;
begin
I := 0;
while (C <> T) and (C <> nil) do begin
C := PLine(C^.dlPrev);
Inc(I);
end;
if C = nil then
Split := 0
else
Split := I;
end;
procedure BigEditor.ResetStream;
begin
Top := PLine(LList^.Head);
TNum := 1;
LOfs := 0;
CPos := 1;
COfs := 0;
SetLongFlag(beOptions, beForceRedraw);
end;
procedure BigEditor.beReadFilePrim(FName : string; var FSize : LongInt;
ErrorPrefix : Word);
label
Skip;
var
Buf : IOBuf;
F : Text;
P : PLine;
I : Integer;
begin
if cwGetLastError <> 0 then
Exit;
if beDefExt <> '' then
FName := DefaultExtension(FName, beDefExt);
Assign(F, FName);
SetTextBuf(F, Buf, MaxFBuf);
Reset(F);
I := IoResult;
if I = ecFileNotFound then
{not found--a new file}
FSize := 0
else begin
if I = ecPathNotFound then
GotError(ErrorPrefix+I, emPathNotFound)
else if I <> 0 then
GotError(ErrorPrefix+I, emOpenError);
if I <> 0 then
Exit;
{check the file size}
FSize := TextFileSize(F);
end;
bePathName := StUpcase(FName);
SetLongFlag(beOptions, beNewFile);
LList^.Clean;
if FSize = 0 then begin
{empty or new file - fake one line}
Str2Asc('', Work^);
New(P, Init(Work));
if P = nil then
GotError(ErrorPrefix+ecOutOfMemory, emInsufficientMemory)
else begin
LList^.Append(P);
ResetStream;
end;
exit;
end;
while not EOF(F) do begin
if not ReadLnAsc(F, Work^) then begin
GotError(ErrorPrefix+ecDiskRead, emReadError);
goto Skip;
end;
New(P, Init(Work));
if P = nil then begin
GotError(ErrorPrefix+ecOutOfMemory, emInsufficientMemory);
goto Skip;
end;
LList^.Append(P);
end;
ResetStream;
ClearLongFlag(beOptions, beModified);
SetLongFlag(beOptions, beForceRedraw);
Skip:
Close(F); if IoResult = 0 then ;
end;
procedure BigEditor.ReadFile(FName : string; var FSize : LongInt);
begin
beReadFilePrim(FName, FSize, epFatal);
end;
procedure BigEditor.SaveFile;
var
Buf : IOBuf;
F : Text;
P : PLine;
I : Word;
B : Boolean;
function MakeBakFile(NewName : string) : Boolean;
var
NF : file;
BakName : string;
I : Integer;
begin
MakeBakFile := False;
if ExistFile(NewName) then begin
BakName := ForceExtension(NewName, 'BAK');
if NewName = BakName then begin
GotError(epNonFatal+ecBadParam, 'Invalid file name');
Exit;
end;
if ExistFile(BakName) then begin
Assign(NF, BakName);
System.Erase(NF);
I := IoResult;
if I <> 0 then begin
GotError(epNonFatal+I, emNoMoreFiles);
exit;
end;
end;
Assign(NF, NewName);
Rename(NF, BakName);
I := IoResult;
if I <> 0 then begin
GotError(epNonFatal+I, emNoMoreFiles);
exit;
end;
end;
MakeBakFile := True;
end;
begin
if bePathName = '' then
Exit;
{make a BAK file?}
if LongFlagIsSet(beOptions, beMakeBackups) then
if not MakeBakFile(bePathName) then exit;
{open the file}
Assign(F, bePathName);
SetTextBuf(F, Buf, MaxFBuf);
Rewrite(F);
I := IoResult;
if I <> 0 then begin
GotError(epNonFatal+I, emOpenError);
Close(F);
I := IoResult;
Exit;
end;
{write the stream to disk}
P := PLine(LList^.Head);
while P <> nil do begin
B := WriteAsc(F, P^.St^);
if not B then begin
GotError(epNonFatal+ecDeviceWrite, emWriteError);
Close(F);
I := IoResult;
Exit;
end;
Write(F, ^M^J);
I := IoResult;
if (I <> 0) then begin
GotError(epNonFatal+I, emWriteError);
Close(F);
I := IoResult;
Exit;
end;
P := PLine(P^.dlNext);
end;
{close the file}
Close(F);
I := IoResult;
if I <> 0 then
GotError(epNonFatal+I, emCloseError)
else
{reset modified flag}
ClearLongFlag(beOptions, beModified);
end;
procedure BigEditor.SaveNamedFile;
var
OP : PathStr;
begin
OP := bePathName;
if GetFile(epMessage+mcSaveAs, emBlockWrite, True, True, True, False,
80, beDefExt, OP) then begin
bePathName := OP;
SaveFile;
SetLongFlag(beOptions, beNewFile);
end;
end;
procedure BigEditor.OfsToPLine(P : PLine);
var
L : PLine;
I : Integer;
begin
L := Top;
I := 0;
while L <> P do begin
L := PLine(L^.dlNext);
Inc(I);
if (I > Height) or (L = nil) then exit;
end;
LOfs := I;
SetLongFlag(beOptions, beForceRedraw);
end;
procedure BigEditor.ChTopLine(Num : Integer);
var
I : Integer;
P : PLine;
begin
if Num >= 0 then begin
P := CurLine;
for I := 1 to Num do
if P^.dlNext <> nil then begin
if Top^.dlNext <> nil then begin
Top := PLine(Top^.dlNext);
Inc(TNum);
end;
if P^.dlNext <> nil then
P := PLine(P^.dlNext)
else if LOfs > 0 then
Dec(LOfs);
end;
end
else for I := 1 to Abs(Num) do
if Top^.dlPrev <> nil then begin
Top := PLine(Top^.dlPrev);
Dec(TNum);
end;
SetLongFlag(beOptions, beForceRedraw);
end;
procedure BigEditor.ChLine(Num : Integer);
var
I : Integer;
P : PLine;
begin
if Num >= 0 then begin
P := CurLine;
for I := 1 to Num do
if LOfs < (Height-1) then begin
if P^.dlNext <> nil then begin
P := PLine(P^.dlNext);
Inc(LOfs);
end;
end
else if P^.dlNext <> nil then
ChTopLine(1);
end
else for I := 1 to Abs(Num) do
if LOfs > 0 then
Dec(LOfs)
else
ChTopLine(-1);
end;
procedure BigEditor.ChCursor(Num : Integer);
var
I : Integer;
begin
if Num >= 0 then begin
for I := 1 to Num do
if CPos < Width then
Inc(CPos)
else if (COfs+Width) < AbsMaxAsciiZ then begin
Inc(COfs);
SetLongFlag(beOptions, beForceRedraw);
end;
end
else for I := 1 to Abs(Num) do
if CPos > 1 then
Dec(CPos)
else if COfs > 0 then begin
Dec(COfs);
SetLongFlag(beOptions, beForceRedraw);
end;
end;
procedure BigEditor.CursorToHome;
begin
CPos := 1;
if COfs <> 0 then begin
COfs := 0;
SetLongFlag(beOptions, beForceRedraw);
end;
end;
procedure BigEditor.CursorToEnd;
begin
Cur := CurLine;
if Cur <> nil then begin
CursorToHome;
if Cur^.lnLen < Width then
CPos := Cur^.Len
else begin
CPos := Width;
COfs := Cur^.Len - Width;
SetLongFlag(beOptions, beForceRedraw);
end;
end;
end;
procedure BigEditor.CursorToCol(Col : Integer);
begin
CursorToHome;
ChCursor(Col);
end;
procedure BigEditor.GetWork(P : Pline);
begin
if P = nil then
Str2Asc('', Work^)
else
MoveFast(P^.St^, Work^, P^.Len);
end;
procedure BigEditor.GetTemp(P : Pline);
begin
if P = nil then
Str2Asc('', Temp^)
else
MoveFast(P^.St^, Temp^, P^.Len);
end;
procedure BigEditor.GetCurLine;
begin
Cur := CurLine;
if Cur = nil then begin
GotError(epFatal+ecStringNotFound, 'Line list corrupted');
exit;
end
else
GetWork(Cur);
end;
procedure BigEditor.GetCurLineTemp;
begin
Cur := CurLine;
if Cur = nil then begin
GotError(epFatal+ecStringNotFound, 'Line list corrupted');
exit;
end
else
GetTemp(Cur);
end;
procedure BigEditor.WordWrap(Src, Ovrlap : AsciiZPtr; Margin : Integer);
var
I : Integer;
begin
FillChar(Ovrlap^, AbsMaxAsciiZ, 0);
I := Margin+1;
{go backwards looking for chars}
while (I > 0) and (not(Src^[i-1] in WrapDelims)) do Dec(I);
{skip whitespace but not other delims}
while (I > 0) and (Src^[i-1] in WrapDelims) do Dec(I);
if (I = 0) or (I > Margin) then
{no worddelims, return "margin" chars of Src with rest in Ovrlap}
I := Margin;
CopyAsc(Src^, I, AbsMaxAsciiZ, Ovrlap^);
DeleteAsc(Src^, I, AbsMaxAsciiZ);
end;
procedure BigEditor.HandleChar(Ch : Char);
label
ErrorOut;
var
W, X : Integer;
P : PLine;
begin
W := CurCol;
GetCurLine;
X := Cur^.lnLen;
if W > X then begin
{cursor past EOL, first pad to length}
AscPad(Work^, W, Temp^);
{add the char}
ConcatStr(Temp^, Ch, Work^);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then goto ErrorOut;
CharsInserted(Cur, X, W-X);
end
else begin
{at or before EOL}
if LongFlagIsSet(beOptions, beInsert) then begin
{insert the char at the cursor}
InsertStr(Ch, Work^, W);
CharsInserted(Cur, W, 1);
end
else begin
{overwrite the char at the cursor with the new char}
Work^[w] := Ch;
if W = X then Work^[w+1] := #0;
end;
{update the string}
Status := Cur^.lnUpdate(Work);
if Status <> 0 then goto ErrorOut;
end;
{update cursor and flags}
SetLongFlag(beOptions, beModified);
ChCursor(1);
if (Ch <> ' ') and
(LongFlagIsSet(beOptions, beWordWrap)) and
(CPos+COfs > beMargin) then begin
{we need to wordwrap the string: first wrap the current line}
WordWrap(Work, Temp, beMargin);
{update the current line}
Status := Cur^.lnUpdate(Work);
if Status <> 0 then goto ErrorOut;
{add our new line}
new(P, Init(Temp));
if P = nil then goto ErrorOut;
LList^.Place(P, Cur);
LinesBroken(Cur, beMargin);
{trim leading whitespace from the overlap}
X := LeadingWhite(P);
if X > 0 then begin
AscTrimLead(P^.St^, Temp^);
Status := P^.lnUpdate(Temp);
if Status <> 0 then goto ErrorOut;
CharsInserted(P, 0, -X);
end;
if LongFlagIsSet(beOptions, beIndent) then begin
{leftpad the overlap string to the indent}
X := LeadingWhite(PLine(P^.dlPrev));
if X > 0 then begin
W := P^.lnLen+X;
GetWork(P);
AscLeftPad(Work^, W, Temp^);
Status := P^.lnUpdate(Temp);
if Status <> 0 then goto ErrorOut;
CharsInserted(P, 0, X);
end;
end;
ChLine(1);
CursorToCol(P^.lnLen);
SetLongFlag(beOptions, beForceRedraw);
end;
exit;
ErrorOut:
if Status = 0 then Status := ecOutOfMemory;
GotError(epNonFatal+Status, emInsufficientMemory);
end;
procedure BigEditor.SplitLinePrim(At : Integer);
{-Splits Work^ at cursor, returning overhang in Temp^}
begin
if At > LenAsc(Work^) then begin
AscPad(Work^, At, Work^);
Str2Asc('', Temp^);
end
else begin
CopyAsc(Work^, At, AbsMaxAsciiZ, Temp^);
DeleteAsc(Work^, At, AbsMaxAsciiZ);
end;
end;
function BigEditor.SplitLine(P : PLine; At : Integer) : PLine;
var
N : PLine;
begin
GetWork(P);
SplitLinePrim(At);
New(N, Init(Temp));
SplitLine := N;
end;
function BigEditor.LeadingWhite(P : PLine) : Integer;
var
I, L : Integer;
begin
GetWork(P);
L := P^.lnLen;
I := 0;
while I < L do begin
if Work^[i] <> ' ' then begin
LeadingWhite := I;
exit;
end;
Inc(I);
end;
LeadingWhite := 0;
end;
procedure Bigeditor.HandleCR(MoveCursor : Boolean);
var
P : PLine;
X : Integer;
At : Integer;
begin
GetCurLine;
At := CurCol;
P := SplitLine(Cur, CurCol);
if (P = nil) then begin
GotError(epNonFatal+ecOutOfMemory, emInsufficientMemory);
exit;
end;
LList^.Place(P, Cur);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
LinesBroken(Cur, At);
if MoveCursor then begin
ChLine(1);
CursorToHome;
if LongFlagIsSet(beOptions, beIndent) then begin
X := LeadingWhite(PLine(P^.dlPrev));
if X > 0 then begin
GetTemp(P);
AscLeftPad(Temp^, X+P^.lnLen, Work^);
Status := P^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
CharsInserted(P, 0, X);
end;
ChCursor(X);
end;
end;
SetLongFlag(beOptions, beForceRedraw+beModified);
end;
procedure BigEditor.HandleTab;
var
L : PLine;
P, I : Integer;
function NextIndentCol(N : PLine; Start : Integer) : Integer;
var
Next : Integer;
Len : Integer;
begin
GetTemp(N);
Len := LenAsc(Temp^);
Next := -1;
if Len > 0 then begin
if (Start < Len) then begin
Next := Start;
if (Temp^[Start] <> ' ') then
{Start is in a word - advance to next blank}
while (Next < Len) and (Temp^[Next] <> ' ') do
Inc(Next);
{In white space - advance to next non-blank}
while (Next < Len) and (Temp^[Next] = ' ') do
Inc(Next);
end
else
{don't go anywhere}
Next := Start;
end;
NextIndentCol := Next;
end;
function FollowingIndent : Word;
var
N : PLine;
begin
FollowingIndent := 0;
N := Cur;
if N^.dlNext <> nil then begin
repeat
N := PLine(N^.dlNext);
until (N = nil) or (N^.lnLen <> 0);
if N <> nil then
FollowingIndent := NextIndentCol(N, 0);
end;
end;
procedure InsertTab(Len, At : Integer);
begin
AscCharStr(' ', Len, Temp^);
InsertAsc(Temp^, Work^, At);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
CursorToCol(At+Len);
CharsInserted(Cur, Len, At);
end;
begin
GetCurLine;
P := CurCol;
if LongFlagIsSet(beOptions, beSmartTabs) then begin
{smart tab: first check previous line}
if Cur = PLine(LList^.Head) then
I := -1
else
I := NextIndentCol(PLine(Cur^.dlPrev), P);
if I > P then
InsertTab(I-P, P)
else if (I < 0) or (P > Cur^.lnLen) then begin
{check following line(s)}
I := FollowingIndent;
if I > P then
InsertTab(I, P);
end;
end
else begin
{do a fixed tab}
I := Pred(beTabSize - (P mod beTabSize));
if I = 0 then I := beTabSize;
InsertTab(I, P);
end;
end;
procedure BigEditor.HandleBS;
var
W : Integer;
P : PLine;
begin
W := CurCol;
GetCurLine;
if W > 0 then begin
DeleteAsc(Work^, W-1, 1);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
ChCursor(-1);
CharsInserted(Cur, W-1, -1);
SetLongFlag(beOptions, beModified);
end
else if Cur^.dlPrev <> nil then begin
P := PLine(Cur^.dlPrev);
LinesJoined(Cur, P^.LnLen);
LList^.Delete(Cur);
W := LenAsc(P^.St^);
ConcatAsc(P^.St^, Work^, Temp^);
Status := P^.lnUpdate(Temp);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
ChLine(-1);
CursorToCol(W);
SetLongFlag(beOptions, beForceRedraw+beModified);
end;
end;
procedure BigEditor.WordLeft;
var
I : Integer;
begin
I := CurCol;
GetCurLine;
if I = 0 then begin
if Cur^.dlPrev <> nil then begin
ChLine(-1);
CursorToEnd;
end;
exit;
end;
if I > Cur^.lnLen then
I := Cur^.lnLen
else begin
while (I > 0) and (Work^[i-1] in WordDelims) do Dec(I);
while (I > 0) and not(Work^[i-1] in WordDelims) do Dec(I);
end;
CursorToCol(I);
end;
procedure BigEditor.WordRight;
var
I, L : Integer;
begin
I := CurCol;
GetCurLine;
L := Cur^.lnLen;
if I >= L then begin
ChLine(1);
CursorToHome;
end
else begin
while (I < L) and not(Work^[i] in WordDelims) do Inc(I);
while (I < L) and (Work^[i] in WordDelims) do Inc(I);
CursorToCol(I);
end;
end;
procedure BigEditor.DelChar;
var
B : Boolean;
begin
GetCurLine;
if CurCol >= Cur^.lnLen then begin
if (LongFlagIsSet(beOptions, beDeleteJoins)) and (Cur^.dlNext <> nil) then begin
AscPad(Work^, CurCol, Temp^);
Cur^.NoTrim := True;
Status := Cur^.lnUpdate(Temp);
Cur^.NoTrim := False;
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
GetTemp(PLine(Cur^.dlNext));
ConcatAsc(Cur^.St^, Temp^, Work^);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
LinesJoined(PLine(Cur^.dlNext), Cur^.lnLen);
LList^.Delete(Cur^.dlNext);
SetLongFlag(beOptions, beForceRedraw+beModified);
end;
exit;
end;
DeleteAsc(Work^, CurCol, 1);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
CharsInserted(Cur, CurCol, -1);
SetLongFlag(beOptions, beModified);
end;
procedure BigEditor.DelEOL;
var
I, L : Integer;
begin
GetCurLine;
L := Cur^.lnLen;
I := CurCol;
DeleteAsc(Work^, I, AbsMaxAsciiZ);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+Status, emInsufficientMemory);
exit;
end;
CharsInserted(Cur, I, -(L-I));
SetLongFlag(beOptions, beModified);
end;
procedure BigEditor.DelWord;
var
I, N, L : Integer;
B : Boolean;
CT : beCharType;
function ClassifyChar(C : Char) : beCharType;
begin
if C in SpaceDelims then
ClassifyChar := beWhite
else if C in WordDelims then
ClassifyChar := bePunct
else
ClassifyChar := beAlpha;
end;
begin
GetCurLine;
I := CurCol;
if I >= Cur^.lnLen then begin
{if we're past EOL, call DelChar to merge the line}
DelChar;
exit;
end;
L := Cur^.lnLen;
N := I;
CT := ClassifyChar(Work^[i]);
while (I < L) and (ClassifyChar(Work^[i]) = CT) do Inc(I);
while (I < L) and (Work^[i] in SpaceDelims) do Inc(I);
DeleteAsc(Work^, N, I-N);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+ecOutOfMemory, emInsufficientMemory);
exit;
end;
CharsInserted(Cur, N, -(I-N));
SetLongFlag(beOptions, beModified);
end;
procedure BigEditor.DelLine;
begin
GetCurLine;
if Cur = PLine(LList^.Tail) then begin
Str2Asc('', Work^);
Status := Cur^.lnUpdate(Work);
if Status <> 0 then begin
GotError(epNonFatal+ecOutOfMemory, emInsufficientMemory);
exit;
end;
LineDeleted(Cur);
CPos := 1;
COfs := 0;
end
else begin
if Top = Cur then begin
Top := PLine(Top^.dlNext);
Inc(TNum);
end;
LineDeleted(Cur);
LList^.Delete(Cur);
end;
CursorToHome;
SetLongFlag(beOptions, beForceRedraw+beModified);
end;
procedure BigEditor.TopOfFile;
begin
Top := PLine(LList^.Head);
TNum := 1;
LOfs := 0;
CursorToHome;
SetLongFlag(beOptions, beForceRedraw);
end;
procedure BigEditor.EndOfFile;
var
I : Integer;
begin
Top := PLine(LList^.Tail);
TNum := LList^.Size;
LOfs := 0;
for I := 1 to Height-1 do
if Top^.dlPrev <> nil then begin
Top := PLine(Top^.dlPrev);
Dec(TNum);
Inc(LOfs);
end;
CursorToEnd;
SetLongFlag(beOptions, beForceRedraw);
end;
procedure BigEditor.GoToLinePtr(P : PLine);
var
I, N : Integer;
begin
if P = nil then exit;
I := LList^.Num(P);
if I = 0 then exit;
Top := P;
TNum := I;
N := LOfs;
for I := 1 to N do
if Top^.dlPrev <> nil then begin
Top := PLine(Top^.dlPrev);
Dec(TNum);
end
else Dec(LOfs);
SetLongFlag(beOptions, beForceRedraw);
end;
procedure BigEditor.GoToLineNum(N : Integer);
var
I, X : Integer;
P : PLine;
begin
if (N < 1) or (N > LList^.Size) then exit;
P := PLine(LList^.Nth(N));
if P = nil then exit;
Top := P;
TNum := N;
X := LOfs;
for I := 1 to X do
if Top^.dlPrev <> nil then begin
Top := PLine(Top^.dlPrev);
Dec(TNum);
end
else Dec(LOfs);
SetLongFlag(beOptions, beForceRedraw);
end;
procedure BigEditor.GoToLineCol(L, C : Integer);
begin
GoToLineNum(L);
CursorToCol(C-1);
end;
procedure BigEditor.DropMarker(L : PLine; C : Integer);
begin
with beLastPosition do begin
LP := L;
CP := C;
end;
end;
procedure BigEditor.SetTextMarker(Num : Integer);
var
P : PLine;
begin
if Num <= MaxMarker then
with beMarkers[Num] do begin
P := CurLine;
if (LP = P) and (CP = CPos+COfs) then begin
LP := nil;
ClearFlag(beMarkerFlags, 1 shl Num);
end
else begin
LP := P;
CP := CPos+COfs;
SetFlag(beMarkerFlags, 1 shl Num);
end;
SetLongFlag(beOptions, beForceRedraw+beMarkersOn);
end;
end;
{-----------------------------------------}
{block, text search/replace and reformatting, and screen update stuff}
{$I OPBIGED.IN1}
{-----------------------------------------}
procedure BigEditor.ProcessSelf;
var
Fin : Boolean;
B : Byte;
S : String;
I : Integer;
SaveCurLine : PLine;
SaveCurCol : Integer;
begin
if cwGetLastError <> 0 then begin
cwCmd := ccError;
Exit;
end;
Draw;
if RawError <> 0 then exit;
{$IFDEF UseMouse}
ShowMouse;
{$ENDIF}
SetLongFlag(beOptions, beInProcess);
DropMarker(CurLine, CurCol);
Fin := False;
with LList^ do repeat
{draw the window}
UpdateContents;
GetNextCommand;
if (LongFlagIsSet(beOptions, beReadOnly)) and (GetLastCommand in DisallowedInReadOnlyMode) then
SetLastCommand(ccNone);
if GetLastCommand = ccCtrlChar then begin
if ColorMono(wTextColor, wTextMono) = ColorMono(beCtrlColor, beCtrlMono) then
cwCmd := ccNone
else begin
BlockCursor;
cwKey := (cwCmdPtr^.cpGetKey and $001F);
case Chr(Lo(cwKey)) of
^M : SetLastCommand(ccSelect);
^J, ^Z : SetLastCommand(ccNone);
else SetLastCommand(ccChar);
end;
if LongFlagIsSet(beOptions, beInsert) then FatCursor else NormalCursor;
end;
end;
SaveCurLine := CurLine;
SaveCurCol := CurCol;
case GetLastCommand of
ccNone:
; {ignore}
{char-oriented ops:}
ccChar:
HandleChar(Chr(Lo(cwKey)));
ccSelect:
HandleCR(True);
ccInsertLine:
HandleCR(False);
ccTab:
HandleTab;
{cursor motion ops:}
ccLeft:
ChCursor(-1);
ccWordLeft:
WordLeft;
ccRight:
ChCursor(1);
ccWordRight:
WordRight;
ccHome:
CursorToHome;
ccEnd:
CursorToEnd;
ccUp:
ChLine(-1);
ccScrollUp:
ChTopLine(-1);
ccScreenTop:
begin
LOfs := 0;
SetLongFlag(beOptions, beForceRedraw);
end;
ccDown:
ChLine(1);
ccScrollDn:
ChTopLine(1);
ccScreenBot:
begin
LOfs := Height-1;
SetLongFlag(beOptions, beForceRedraw);
end;
ccPageUp:
if Top = PLine(LList^.Head) then
TopOfFile
else
ChTopLine(-(Height-1));
ccPageDn:
ChTopLine(Height-1);
ccTopOfFile:
TopOfFile;
ccEndOfFile:
EndOfFile;
ccJmpLine:
begin
S := Long2Str(TNum+LOfs);
if Edit(mcLineNumber, emLineNumber, True, True, 5, S) then
if Str2Int(S, I) then
GoToLineNum(I);
end;
ccJmpBegin:
if beBlockBegin.LP <> nil then begin
GoToLineCol(LList^.Num(beBlockBegin.LP), beBlockBegin.CP);
OfsToPLine(beBlockBegin.LP);
end;
ccJmpEnd:
if beBlockEnd.LP <> nil then begin
GoToLineCol(LList^.Num(beBlockEnd.LP), beBlockEnd.CP+1);
OfsToPLine(beBlockEnd.LP);
end;
ccPrevPos:
with beLastPosition do
if LP <> nil then begin
GoToLinePtr(LP);
CursorToCol(CP);
OfsToPLine(LP);
end;
{deletion ops}
ccBack:
HandleBS;
ccDel:
DelChar;
ccDelWord:
DelWord;
ccDelEOL:
DelEOL;
ccDelLine:
DelLine;
{search/replace ops:}
ccSearch:
TextSearch(True, bescSearch);
ccReplace:
TextSearch(True, bescReplace);
ccReSearch:
TextSearch(False, bescSearch);
{reformatting:}
ccReformatP:
ReformatParagraph;
ccReformatG:
ReformatGlobal;
ccCenterLine:
CenterLine;
{block-oriented ops:}
ccBlkBegin:
with beBlockBegin do begin
LP := CurLine;
CP := CurCol;
if BlockContiguous then begin
ConnectBlocking;
SetLongFlag(beOptions, beBlockOn);
end
else begin
CleanBlocking;
ClearLongFlag(beOptions, beBlockOn);
end;
SetLongFlag(beOptions, beForceRedraw);
end;
ccBlkEnd:
with beBlockEnd do begin
LP := CurLine;
CP := CurCol;
if LP^.lnLen < CP then
CP := LP^.lnLen;
if BlockContiguous then begin
ConnectBlocking;
SetLongFlag(beOptions, beBlockOn);
end
else begin
CleanBlocking;
ClearLongFlag(beOptions, beBlockOn);
end;
SetLongFlag(beOptions, beForceRedraw);
end;
ccBlkToggle:
begin
if BlockContiguous then
beToggleOption(beBlockOn)
else begin
CleanBlocking;
ClearLongFlag(beOptions, beBlockOn);
end;
SetLongFlag(beOptions, beForceRedraw);
end;
ccBlkWord:
MarkWordAsBlock;
ccBlkCopy:
CopyBlock;
ccBlkMove:
MoveBlock;
ccBlkDelete:
DeleteBlock;
ccBlkIndent:
IndentBlock(beBlockIndent);
ccBlkUnindent:
IndentBlock(-beBlockIndent);
ccBlkUCase:
ChangeCaseBlock(beToUpper);
ccBlkLCase:
ChangeCaseBlock(beToLower);
ccBlkTCase:
ChangeCaseBlock(beToggle);
ccBlkRead:
ReadBlock;
ccBlkWrite:
WriteBlock(False);
ccBlkPrint:
WriteBlock(True);
{clipboard ops:}
ccCopyClip:
CopyToClipboard(False);
ccCutClip:
CopyToClipboard(True);
ccPasteClip:
PasteFromClipboard;
{text marker stuff:}
ccMarkToggle:
begin
beToggleOption(beMarkersOn);
SetLongFlag(beOptions, beForceRedraw);
end;
ccSetMark0..ccSetMark9:
begin
B := GetLastCommand - ccSetMark0;
SetTextMarker(B);
end;
ccJmpMark0..ccJmpMark9:
begin
B := GetLastCommand - ccJmpMark0;
if B <= MaxMarker then
with beMarkers[b] do
if LP <> nil then begin
GoToLineCol(LList^.Num(LP), CP);
SetLongFlag(beOptions, beForceRedraw+beMarkersOn);
end;
end;
{file ops:}
ccNewFile:
NewFilePrompted;
ccSaveFile:
if bePathName <> '' then
SaveFile;
ccSaveNamed:
if bePathName <> '' then
SaveNamedFile;
ccSaveSwitch:
if bePathName <> '' then begin
SaveFile;
if cwGetLastError = 0 then begin
beStatus(@self);
NewFilePrompted;
end;
end;
ccSaveExit:
if bePathName <> '' then begin
SaveFile;
Fin := True;
end;
{$IFDEF UseMouse}
ccMouseAuto,
ccMouseDown,
ccMouseSel :
if cwCmdPtr^.MouseEnabled then
Fin := ProcessMouseCommand(cwCmd);
{$ENDIF}
{other misc. operations:}
ccIns:
beToggleOption(beInsert);
ccIndent:
beToggleOption(beIndent);
ccTabToggle:
beToggleOption(beSmartTabs);
ccWordWrap:
beToggleOption(beWordWrap);
ccRtMargin:
begin
S := Long2Str(beMargin);
if Edit(mcRightMargin, emRightMargin, True, True, 5, S) then
if Str2Int(S, I) then
if (I > 0) then
beMargin := I;
end;
ccTabSize:
begin
S := Long2Str(beTabSize);
if Edit(mcTabSize, emTabSize, True, True, 3, S) then
if Str2Int(S, I) then
if (I > 0) and (I <= 255) then
beTabSize := I;
end;
ccSetIndent:
begin
S := Long2Str(beBlockIndent);
if Edit(mcIndentLevel, emIndentLevel, True, True, 3, S) then
if Str2Int(S, I) then
if (I > 0) and (I <= 10) then
beBlockIndent := I;
end;
ccHelp :
RequestHelp(wHelpIndex);
{exit commands:}
ccUser0..ccUser65335,
ccAbandonFile,
ccQuit:
Fin := True;
else if (cwCmd <= 255) and (GetExitCommandPtr <> nil) then
{Possibly a special exit command defined by a derived object}
Fin := (cwCmd in GetExitCommandPtr^);
end;
{fix beLastPosition if necessary}
if beLastPosition.LP = nil then
DropMarker(Top, 0)
else case cwCmd of
ccBlkCopy,
ccBlkMove,
ccBlkDelete,
ccBlkRead :
{do nothing} ;
else
if SaveCurLine <> CurLine then
DropMarker(SaveCurLine, SaveCurCol);
end;
until Fin or (cwCmd = ccError);
UpdateContents;
{$IFDEF UseMouse}
HideMouse;
{$ENDIF}
rwSaveWindowState;
ClearLongFlag(beOptions, beInProcess);
end;
begin
{make sure we don't get too long a line}
if MaxAsciiZ < AbsMaxAsciiZ then
AbsMaxAsciiZ := MaxAsciiZ;
Clipboard.Init;
BigEditorCommands.Init(@BigEditorKeySet, BigEditorKeyMax);
end.